"""
Copyright 2009, Thomas Dejanovic, Jay Shurtz.
 
This is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of
the License, or (at your option) any later version.

This software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this software; if not, write to the Free
Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
02110-1301 USA, or see the FSF site: http://www.fsf.org.

This is the most specific level of xml generation for register
hatchlings.  it contains information about how to generate and
write xml from the hatchling data structure.
"""

id = "$Id: hatch_python.py 667 2010-07-01 00:12:17Z jayshurtz $"
# $URL: http://hatch.googlecode.com/svn/tags/taggle_release_3.0/hatch/hatch_targets/hatch_python.py $
# $Author: jayshurtz $
version = " ".join(id.split()[1:3])

from os import extsep
import to_hatch_structure
from hatch_log import *
from hatch_constants import TOP_NODE, GLOBAL_NAME, PARENT_ATTRIBUTE, PROPERTIES_ATTRIBUTE


GLOBAL_KEYWORD = 'global'   # Python keyword.


class HatchPythonGenerator(object):
    """ """
    def generate(self, hatchNode, moduleName):
        """ Generate hatch code (python) from a hatchNode. The hatch code that is generated is very plain and sequential,
            and can itself be used as a hatch design file.
            This is useful for checking that a design is being interpreted correctly (run it twice & diff the results.)
            This is also useful as an intermediate step when "un-hatching" designs, for example converting xml or 
            verilog back into python hatch code.
            'hatchNode' is the top node of the design.
            'moduleName' is the basename of the design file.
        """
        logger.info(self.generate.func_name + "(" + hatchNodeClassAndName(hatchNode) + ", " + str(moduleName) + ")")
        documentLines = [GLOBAL_KEYWORD + " " + TOP_NODE]
        unique_name = hatchNode.properties[GLOBAL_NAME]   # Raises error if property elaborator has not set a unique name property.
        parentUniqueName = str(None)
        if hatchNode.parent is not None:
            parentUniqueName = hatchNode.parent.properties[GLOBAL_NAME]
        self.generate_hatchling_python(hatchNode, unique_name, parentUniqueName, documentLines)    # Note: hatchNode.parent should be None (top-level node.)
        documentLines += [TOP_NODE + ' = ' + unique_name]
        outputFile = open(moduleName.replace('_hatch','_hatched') + extsep + "py", 'w') # XXX This will need to be changed if makefiles change.
        outputFile.write("\n".join(documentLines))  # Write to file.  
        outputFile.close()

    def generate_hatchling_python(self, hatchNode, unique_name, parentUniqueName, doc):
        """ Recurse through hatchling contents to get all HatchNode instances.
            Generate python along the way by adding to the document.
            'hatchNode' is the current HatchNode.
            'parent' is the parent of the current hatchling.
            'doc' is a list of lines in the document.
        """
        #doc.append('# Bla bla.')    # Write a comment.
        doc.append(unique_name + ' = ' + hatchNode.__class__.__name__ + "('" + hatchNode.name + "')")   # Code python for instantiation of node.
        doc.append(unique_name + "." + PARENT_ATTRIBUTE + ' = ' + parentUniqueName)   # Code python for node parent.
        for (k, v) in sorted(hatchNode.properties.items()): # Code python for node properties.
            #try:    # Duck typing.
            doc.append(unique_name + "." + PROPERTIES_ATTRIBUTE + "['" + str(k) + "'] = " + repr(v))
            #except TypeError, e:
            #    doc.append(unique_name + ".properties['" + str(k) + "'] = " + v.__class__.__name__ + '(' + repr(v) + ')'    # Not a basic data type.
        for childNode in hatchNode.childNodes:
            unique_name_child = childNode.properties[GLOBAL_NAME] 
            self.generate_hatchling_python(childNode, unique_name_child, unique_name, doc)


def generate(hatchNode, moduleName):
    """ Called by hatch.
        'hatchNode' is the top node of the design.
        'moduleName' is the basename of the design file.
    """
    hpg = HatchPythonGenerator()
    hpg.generate(hatchNode, moduleName)


# TODO - built-in-self-test 
if __name__ == "__main__":
    #import hatch_history
    #hatch_history.setupSimpleHistory(histfile=__file__.replace('.py','.pyhist'), length=500)  # Setup history for this file.
    consoleHandler.setLevel(logging.DEBUG)

    try:
        from hatch_nodes.hatch_node_physical import *
    except ImportError, e:
        raise ImportError, str(e) + "\nAdd hatch_nodes to your PYTHONPATH with 'export PYTHONPATH=$PYTHONPATH:hatch/tools/hatch/hatch_nodes'."

    h0 = HatchNodePhysical('h0', global_name='h0', bit_width=8, stringProp='hey!')
    h1 = HatchNodePhysical('h0', global_name='h1', bit_width=10, stringProp='hey!!')
    h2 = HatchNodePhysical('h0', global_name='h2', bit_width=24)
    h3 = HatchNodePhysical('h0', global_name='h3', bit_width=32)
    h0h1 = HatchNodePhysical('h0', h0, h1, global_name='h0h1')
    h2h0h1 = HatchNodePhysical('h0', h2, h0h1, global_name='h2h0h1')
    hatchBlock = HatchNodePhysical('h0', h3, h2h0h1, global_name='hatchBlock')

    generate(hatchBlock, 'hatch_python_test')


